# Required packages
import pandas as pd
import numpy as np
import geopandas as gpd
import json
import os
import pickle
## Visualisation libraries
# Maps
import geoplot as gplt
import geoplot.crs as gcrs
import mplleaflet
from shapely.geometry import Point, Polygon
import folium
from folium import plugins
from folium.plugins import HeatMap
## Text
from colorama import Fore, Back, Style
from IPython.display import Image, display, Markdown, Latex, clear_output
## progressbar
import progressbar
## plotly
from plotly.offline import init_notebook_mode, iplot
import plotly.graph_objs as go
import plotly.offline as py
from plotly.subplots import make_subplots
import plotly.express as px
## seaborn
import seaborn as sns
## matplotlib
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse, Polygon
from matplotlib.font_manager import FontProperties
import matplotlib.colors as mcolors
plt.style.use('seaborn-whitegrid')
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12
plt.rcParams['text.color'] = 'k'
%matplotlib inline
import warnings
warnings.filterwarnings("ignore")
The assessed values of residential, non-residential, and farmland properties in Calgary. The properties in this dataset consist of Calgary lands that have a registered parcel at Alberta’s Land Titles Office. Properties that are on The City of Calgary’s annual property assessment rolls, but excluded from this dataset, are titled parking stalls, titled storage units, machinery & equipment property, and linear property (as defined in the Municipal Government Act). This dataset can be downloaded from here.
For detailed property assessment information, visit https://assessmentsearch.calgary.ca
Path = 'Calgary/Property_Assessments.csv'
def Header(Text, L = 100, C = 'Blue', T = 'White'):
BACK = {'Black': Back.BLACK, 'Red':Back.RED, 'Green':Back.GREEN, 'Yellow': Back.YELLOW, 'Blue': Back.BLUE,
'Magenta':Back.MAGENTA, 'Cyan': Back.CYAN}
FORE = {'Black': Fore.BLACK, 'Red':Fore.RED, 'Green':Fore.GREEN, 'Yellow':Fore.YELLOW, 'Blue':Fore.BLUE,
'Magenta':Fore.MAGENTA, 'Cyan':Fore.CYAN, 'White': Fore.WHITE}
print(BACK[C] + FORE[T] + Style.NORMAL + Text + Style.RESET_ALL + ' ' + FORE[C] +
Style.NORMAL + (L- len(Text) - 1)*'=' + Style.RESET_ALL)
def Line(L=100, C = 'Blue'):
FORE = {'Black': Fore.BLACK, 'Red':Fore.RED, 'Green':Fore.GREEN, 'Yellow':Fore.YELLOW, 'Blue':Fore.BLUE,
'Magenta':Fore.MAGENTA, 'Cyan':Fore.CYAN, 'White': Fore.WHITE}
print(FORE[C] + Style.NORMAL + L*'=' + Style.RESET_ALL)
def Search_List(Key, List): return [s for s in List if Key in s]
Data = pd.read_csv(Path.split(".")[0]+'_Mod.csv')
Header('Calgary Property Assessments:')
display(Data.head(4).style.hide_index())
display(pd.DataFrame({'Number of Instances': [Data.shape[0]], 'Number of Attributes': [Data.shape[1]]}).style.hide_index())
# Dictionaries
with open(Path.split(".")[0] + '_Feat_Dict.pkl', 'rb') as fp:
Feat_Dict = pickle.load(fp)
display(pd.DataFrame({'Feature': Feat_Dict.keys(), 'Description': Feat_Dict.values()}).style.hide_index())
Calgary Property Assessments: ======================================================================
| Roll_Year | Roll_Number | Address | Assessed_Value | Assessment_Class | Assessment_Class_Description | RE_Assessed_Value | NR_Assessed_Value | FL_Assessed_Value | Community_Code | Community_Name | Latitude | Longitude | Unique_Key | Year_Of_Construction | Land_Use_Designation | Property_Type | Land_Size_SM | Land_Size_SF | Land_Size_AC | Sub_Property_Use | Point | Community_Structure | Sector | Class_Code | Srg | Class |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2019 | 202658902 | 215 4350 SETON DR SE | 220000.000000 | RE | Residential | 220000.000000 | nan | nan | SET | Seton | 50.877365 | -113.947337 | 2019202658902 | nan | nan | nan | nan | nan | nan | nan | POINT (-113.947336601944 50.877364528547) | Building Out | Southeast | 1 | Developing | Residential |
| 2020 | 202682290 | 29V 230 SETON PS SE | 10000.000000 | RE | Residential | 10000.000000 | nan | nan | SET | Seton | 50.879463 | -113.947337 | 2020202682290 | nan | M-1 | LO | 14.000000 | 151.000000 | 0.000000 | TPU | nan | Building Out | Southeast | 1 | Developing | Residential |
| 2019 | 202681714 | 192V 19621 40 ST SE | 10000.000000 | RE | Residential | 10000.000000 | nan | nan | SET | Seton | 50.879463 | -113.947337 | 2019202681714 | nan | nan | nan | nan | nan | nan | nan | nan | Building Out | Southeast | 1 | Developing | Residential |
| 2019 | 202681938 | 214V 19621 40 ST SE | 10000.000000 | RE | Residential | 10000.000000 | nan | nan | SET | Seton | 50.879463 | -113.947337 | 2019202681938 | nan | nan | nan | nan | nan | nan | nan | nan | Building Out | Southeast | 1 | Developing | Residential |
| Number of Instances | Number of Attributes |
|---|---|
| 7849557 | 27 |
| Feature | Description |
|---|---|
| Roll_Year | Assessment Roll Year |
| Roll_Number | Assessment Account Roll Number |
| Address | Civic Address |
| Assessed_Value | Total Assessed Value of the Property |
| Assessment_Class | Predominant Assessment Class Code |
| Assessment_Class_Description | Description of Predominant Assessment Class |
| RE_Assessed_Value | Assessed Value of Residential Property |
| NR_Assessed_Value | Assessed Value of Non-Residential Property |
| FL_Assessed_Value | Assessed Value Of Farmland |
| Community_Code | Community Code |
| Community_Name | Community Name |
| Latitude | Latitude |
| Longitude | Longitude |
| Unique_Key | Unique Key |
| Year_Of_Construction | Account AYOC (Actual Year of Construction) |
| Land_Use_Designation | Land Use Designation |
| Property_Type | Account Property Type |
| Land_Size_SM | Account Assessable Land Area Square Meters |
| Land_Size_SF | Account Assessable Land Area Square Feet |
| Land_Size_AC | Account Assessable Land Area Square Acres |
| Sub_Property_Use | Account Sub Property Type |
| Point | Point |
We can also use the community boundaries for the city of Calgary from here.
Community_Boundaries = gpd.read_file('Calgary/Community_Boundaries.geojson')
# Chaning the headers to title
mylist = Community_Boundaries.columns.tolist()
mylist = [x.replace('comm_','Community_').title() for x in mylist]
mylist = [x.replace('Geometry','geometry') for x in mylist]
Community_Boundaries.columns = mylist
del mylist
display(Community_Boundaries.head(4))
| Community_Structure | Name | Sector | Class_Code | Srg | Class | Community_Code | geometry | |
|---|---|---|---|---|---|---|---|---|
| 0 | INNER CITY | SUNALTA | CENTRE | 1 | BUILT-OUT | Residential | SNA | POLYGON ((-114.10061 51.04799, -114.10056 51.0... |
| 1 | BUILDING OUT | WEST SPRINGS | WEST | 1 | DEVELOPING | Residential | WSP | POLYGON ((-114.18781 51.06151, -114.18781 51.0... |
| 2 | OTHER | 12A | SOUTHEAST | 4 | N/A | Residual Sub Area | 12A | POLYGON ((-113.86945 50.97957, -113.86945 50.9... |
| 3 | 1950s | WINDSOR PARK | CENTRE | 1 | BUILT-OUT | Residential | WND | POLYGON ((-114.08152 51.00872, -114.08137 51.0... |
First, of all the dataset includes the following assessment roll years.
Years = np.sort(Data.Roll_Year.unique())
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(16, 0.25), sharex=False)
_ = sns.boxplot(x=Years, ax=ax, orient='h', color='#2ecc71')
_ = ax.set_xlabel('Years')
_ = ax.set_xlim([Years.min(), Years.max()])
_ = ax.set_xticks(Years)
_ = ax.grid('off')
In particular, in each year:
def FeatDispPlot2(Feat, Title, LC = 'Black',
Colors = ['HoneyDew','GreenYellow', 'Bisque','LightSalmon','Plum', 'LightSkyBlue'],
yLim = [0, 9e3], H = 450, titleY = 0.92, Inp = Data):
Group = Inp.groupby([Feat])[Feat].agg({'count'}).rename(columns = {'count':'Count'})
Group['Percentage'] = np.round(100* Group.values /Group.sum().values, 2)
Group.reset_index(drop = False, inplace = True)
fig = make_subplots(rows=1, cols=2, horizontal_spacing = 0.05,
column_widths=[0.6, 0.4],specs=[[{"type": "xy"}, {'type':'domain'}]])
# Left
fig.add_trace(go.Bar(x= Group[Feat].values, y= Group['Count'].values,
marker_color= Colors, text = 'Count',
textposition='inside', showlegend = False, hovertext=list(Group['Percentage'])), 1, 1)
fig.update_layout(plot_bgcolor= 'white')
fig.update_traces(marker_line_color= LC, marker_line_width=1, opacity=1,
texttemplate= 10*' ' + '%{value}', textposition='inside', row=1, col=1)
fig.update_xaxes(showline=True, linewidth=1, linecolor='Lightgray', mirror=True,
zeroline=False, zerolinewidth=1, zerolinecolor='Black',
showgrid=False, gridwidth=1, gridcolor='Lightgray')
fig.update_yaxes(showline=True, linewidth=1, linecolor='Lightgray', mirror=True,
zeroline=True, zerolinewidth=1, zerolinecolor='Black',
showgrid=True, gridwidth=1, gridcolor='Lightgray', range= yLim)
# Right
fig.add_trace(go.Pie(labels= Group[Feat].values, values= Group['Count'].values, textfont=dict(size=16),
marker=dict(colors = Colors, line=dict(color='black', width=1))), 1, 2)
fig.update_traces(marker_line_color= LC, marker_line_width=1, opacity=1, row=1, col=2)
fig.update_layout(plot_bgcolor= 'white', width = 900,
title={'text': '<b>' + Title + '<b>',
'x':0.5, 'y':0.90, 'xanchor': 'center', 'yanchor': 'top'})
fig.show()
def Roll_Number_Data (rn):
Out = Data[Data.Roll_Number == rn].sort_values(by='Roll_Year', ascending=True).reset_index(drop =True)
Cols = Out.isna().sum()
Cols = Cols.loc[(Cols>0) & (Cols< Cols.max())]
Cols = Cols.index
Temp = Out[Cols]
Out[Cols] = Temp.fillna(value=dict(zip(Temp.columns, Temp.dropna().values[0])))
return Out
def Roll_Number_Table(Inp):
Replace_Dict = {'Roll_Year':'Year','Assessment_Class_Description':'Class', '_':' ', 'Of':'of',
'Srg':'SRG'}
Temp = Inp.columns
for key in list(Replace_Dict.keys()):
Temp = [x.replace(key,Replace_Dict[key]) for x in Temp]
Inp.columns = Temp
Featured_Cols = ['Year','Address', 'Assessed Value','Land Size SF', 'Class', 'Community Name', 'Year of Construction','Community Structure', 'Sector', 'SRG']
Inp = Inp[Featured_Cols]
try:
Inp[['Year of Construction','Land Size SF']] = Inp[['Year of Construction','Land Size SF']].astype('int32')
except:
pass
Inp = Inp.reset_index(drop = True)
display(Inp.style.hide_index().set_precision(0).bar(subset=['Assessed Value'], align='left', color=['Lime'])\
.set_properties(subset=['Year'], **{'background-color': 'Indigo', 'color': 'White'}))
def address_map(Inp, Zoom=12.5, Icon='info-sign'):
m = folium.Map(location=[Inp.Latitude[0], Inp.Longitude[0]], zoom_start=Zoom)
folium.Marker(location=[Inp.Latitude[0], Inp.Longitude[0]],popup = Inp.Address[0],
icon=folium.Icon(icon=Icon)).add_to(m)
display(m)
return
def Unit_Price(Inp):
fig, ax = plt.subplots(figsize=(14,5))
fig = sns.regplot(x='Roll_Year', y='Assessed_Value', data=Inp, color='#e74c3c',
scatter_kws={'s': 50, 'color': '#34495e'},order=10, ci=None, truncate=False)
_ = ax.set_title('The Price Fluctuations for %s Unit at %s (%s)' % (Inp.Assessment_Class_Description.tolist()[-1],
Inp.Address.tolist()[-1],
Inp.Comm_Name.unique()[0]))
_ = ax.set_ylabel('Assessed')
_ = ax.set_xlabel('Price')
_ = ax.set_xticks(np.arange(Inp.Roll_Year.min(),Inp.Roll_Year.max()+1,1))
def Community_Ave_yr(Yr = 2021, Sort = True, Inp = Data, Boundaries = Community_Boundaries):
Temp = Inp[Inp['Roll_Year'] == Yr]
Cols = ['Community_Code', 'Community_Name', 'Assessment_Class_Description', 'Community_Structure', 'Sector']
Group = Temp.groupby(Cols)['Assessed_Value'].agg({'mean','median', 'max', 'min'})
Group = Group.rename(columns = {'mean':'Average Value', 'median':'Median Value', 'max':'Maximum Value', 'min':'Minimum Value'})
Group = Group.reset_index(drop = False)
Out = Group.merge(Boundaries [['Community_Code', 'geometry']], how='right', on='Community_Code')
Out = Out[pd.notnull(Out['Average Value'])]
Out.columns = [x.replace('_',' ') for x in Out.columns]
if Sort:
Out = Out.sort_values(by='Average Value', ascending=False)
return Out
FeatDispPlot2('Roll_Year', Title = 'The Number of Rolling by Year', yLim = [0, 6e5],
Colors = px.colors.qualitative.Light24)
Consider the assessed values only in the current year:
Current_year = Data[Data['Roll_Year']==Data['Roll_Year'].max()].sort_values(by = ['Assessed_Value'], ascending= False)
For the most expensive unit we have,
rn = Current_year['Roll_Number'].values[0]
Table = Roll_Number_Data(rn).drop(columns = ['Class'])
Roll_Number_Table(Table)
address_map(Table, 15.5)
print('As can be seen the unit is a %s unit, and it is located in %s.' % (Table['Class'].values[-1],
Table['Community Name'].values[-1]))
| Year | Address | Assessed Value | Land Size SF | Class | Community Name | Year of Construction | Community Structure | Sector | SRG |
|---|---|---|---|---|---|---|---|---|---|
| 2010 | 4448 FRONT ST SE | 3500000 | 1427341 | Non-residential | Seton | 2007 | Building Out | Southeast | Developing |
| 2011 | 4448 FRONT ST SE | 5610000 | 1427341 | Non-residential | Seton | 2007 | Building Out | Southeast | Developing |
| 2012 | 4448 FRONT ST SE | 6550000 | 1427341 | Non-residential | Seton | 2007 | Building Out | Southeast | Developing |
| 2013 | 4448 FRONT ST SE | 6550000 | 1427341 | Non-residential | Seton | 2007 | Building Out | Southeast | Developing |
| 2014 | 4448 FRONT ST SE | 745840000 | 1427341 | Non-residential | Seton | 2007 | Building Out | Southeast | Developing |
| 2015 | 4448 FRONT ST SE | 933320000 | 1427341 | Non-residential | Seton | 2007 | Building Out | Southeast | Developing |
| 2016 | 4448 FRONT ST SE | 930080000 | 1427341 | Non-residential | Seton | 2007 | Building Out | Southeast | Developing |
| 2017 | 4448 FRONT ST SE | 932400000 | 1427341 | Non-residential | Seton | 2007 | Building Out | Southeast | Developing |
| 2018 | 4448 FRONT ST SE | 1449330000 | 1427341 | Non-residential | Seton | 2007 | Building Out | Southeast | Developing |
| 2019 | 4448 FRONT ST SE | 1482170000 | 1427341 | Non-residential | Seton | 2007 | Building Out | Southeast | Developing |
| 2020 | 4448 FRONT ST SE | 1492130000 | 1427341 | Non-residential | Seton | 2007 | Building Out | Southeast | Developing |
| 2021 | 4448 FRONT ST SE | 1498350000 | 1427341 | Non-residential | Seton | 2007 | Building Out | Southeast | Developing |
As can be seen the unit is a Non-residential unit, and it is located in Seton.
The following function can be used for calculating the Average Value of each community.
Community_Ave = Community_Ave_yr(Sort = True)
Community_Ave.iloc[:,:-1].head(15).style.format({'Maximum Value': "{:.2e}", 'Minimum Value': "{:.2e}",
'Median Value': "{:.2e}", 'Average Value': "{:.2e}"}).hide_index().\
background_gradient(subset= ['Average Value'], cmap='GnBu')
| Community Code | Community Name | Assessment Class Description | Community Structure | Sector | Median Value | Maximum Value | Minimum Value | Average Value |
|---|---|---|---|---|---|---|---|---|
| DNW | Downtown West End | Machinery And Equipment | Centre City | Centre | 3.66e+08 | 3.66e+08 | 3.66e+08 | 3.66e+08 |
| EAG | Eagle Ridge | Non-residential | 1960S/1970S | South | 1.28e+05 | 4.18e+08 | 8.75e+04 | 1.39e+08 |
| MEA | Meadowlark Park | Non-residential | 1950S | Centre | 3.54e+05 | 1.14e+09 | 2.70e+03 | 9.52e+07 |
| SET | Seton | Non-residential | Building Out | Southeast | 3.31e+06 | 1.50e+09 | 2.15e+04 | 5.23e+07 |
| UOC | University Of Calgary | Non-residential | Other | Northwest | 8.19e+05 | 7.22e+08 | 1.62e+04 | 4.80e+07 |
| 12B | Residual Ward 12 - Sub Area 12B | Non-residential | Undeveloped | Southeast | 4.96e+05 | 8.00e+08 | 0.00e+00 | 4.40e+07 |
| COP | Canada Olympic Park | Non-residential | Other | West | 4.02e+06 | 1.27e+08 | 9.43e+05 | 4.38e+07 |
| NPK | Nose Hill Park | Non-residential | Parks | Northwest | 5.02e+06 | 2.09e+08 | 3.70e+04 | 3.44e+07 |
| EAU | Eau Claire | Non-residential | Centre City | Centre | 1.84e+06 | 4.51e+08 | 0.00e+00 | 3.34e+07 |
| 09P | Residual Ward 9 - Sub Area 9P | Non-residential | Undeveloped | East | 4.59e+06 | 1.45e+08 | 3.74e+03 | 3.32e+07 |
| HSN | Haskayne | Non-residential | Building Out | Northwest | 3.50e+04 | 3.41e+08 | 0.00e+00 | 3.18e+07 |
| UOC | University Of Calgary | Residential | Other | Northwest | 2.95e+07 | 4.32e+07 | 1.36e+07 | 2.93e+07 |
| 02E | Residual Ward 2 - Sub Area 2E | Non-residential | Other | Northwest | 6.43e+06 | 1.49e+08 | 9.35e+05 | 2.73e+07 |
| QPK | Queens Park Village | Residential | 1950S | Centre | 2.66e+07 | 2.66e+07 | 2.66e+07 | 2.66e+07 |
| LPK | Lincoln Park | Non-residential | 1950S | West | 3.84e+06 | 3.13e+08 | 2.90e+04 | 2.24e+07 |
def AvgValueClass_Plot(Class, H = 600, Top = 40, yt = None, Community_Ave = Community_Ave, Horizontal = True,
marker_color='rgba(58, 71, 80, 0.6)', marker_line_color='rgba(58, 71, 80, 1.0)'):
Group = Community_Ave[Community_Ave['Assessment Class Description'] == Class][['Community Name','Average Value']]
if not Top == None:
if Group.shape[0]>Top:
Group = Group.head(40)
if yt == None:
yt = Group['Average Value'].max()
n = (len(str(int(yt))) -1)
yt = int(np.ceil(yt/(10**n))*(10**n))
if Horizontal:
fig = px.bar(Group, x='Community Name', y='Average Value')
fig.update_xaxes(showline=True, linewidth=1, linecolor='Lightgray', mirror=True,
zeroline=False, zerolinewidth=1, zerolinecolor='Black',
showgrid=False, gridwidth=1, gridcolor='Lightgray')
fig.update_yaxes(showline=True, linewidth=1, linecolor='Lightgray', mirror=True,
zeroline=True, zerolinewidth=1, zerolinecolor='Black',
showgrid=True, gridwidth=1, gridcolor='Lightgray', range= [0, yt])
else:
fig = px.bar(Group, y='Community Name', x='Average Value')
fig.update_yaxes(showline=True, linewidth=1, linecolor='Lightgray', mirror=True,
zeroline=False, zerolinewidth=1, zerolinecolor='Black',
showgrid=False, gridwidth=1, gridcolor='Lightgray')
fig.update_xaxes(showline=True, linewidth=1, linecolor='Lightgray', mirror=True,
zeroline=True, zerolinewidth=1, zerolinecolor='Black',
showgrid=True, gridwidth=1, gridcolor='Lightgray', range= [0, yt])
fig.update_traces(marker_color=marker_color, marker_line_color=marker_line_color,
marker_line_width=1.5, opacity=1)
fig.update_layout(plot_bgcolor= 'white', height= H, width = 980,
title={'text': '<b>' + 'Average Value (%s)' % Class + '<b>',
'x':0.5, 'y':0.95, 'xanchor': 'center', 'yanchor': 'top'})
fig.show()
def AvgValue_Plot(Feat, H = 600, Top = 40, yt = None, Community_Ave = Community_Ave,
marker_color='rgba(58, 71, 80, 0.6)', marker_line_color='rgba(58, 71, 80, 1.0)'):
Group = pd.DataFrame(Community_Ave.groupby([Feat])['Average Value'].mean()).reset_index()
if not Top == None:
if Group.shape[0]>Top:
Group = Group.head(40)
if yt == None:
yt = Group['Average Value'].max()
n = (len(str(int(yt))) -1)
yt = int(np.ceil(yt/(10**n))*(10**n))
fig = px.bar(Group, x='Average Value', y= Feat)
fig.update_yaxes(showline=True, linewidth=1, linecolor='Lightgray', mirror=True,
zeroline=False, zerolinewidth=1, zerolinecolor='Black',
showgrid=False, gridwidth=1, gridcolor='Lightgray')
fig.update_xaxes(showline=True, linewidth=1, linecolor='Lightgray', mirror=True,
zeroline=True, zerolinewidth=1, zerolinecolor='Black',
showgrid=True, gridwidth=1, gridcolor='Lightgray', range= [0, yt])
fig.update_traces(marker_color=marker_color, marker_line_color=marker_line_color,
marker_line_width=1.5, opacity=1)
fig.update_layout(plot_bgcolor= 'white', height= H, width = 980,
title={'text': '<b>' + 'Average Value (%s)' % Feat + '<b>',
'x':0.5, 'y':0.95, 'xanchor': 'center', 'yanchor': 'top'})
fig.show()
AvgValueClass_Plot(Class = 'Non-residential', Top = 50, yt = 160e6)
AvgValueClass_Plot(Class = 'Residential', marker_color='rgb(158,202,225)', marker_line_color='rgb(8,48,107)')
AvgValueClass_Plot(Class = 'Farm land', marker_color='rgb(173,255,47)', marker_line_color='rgb(34,139,34)')
AvgValueClass_Plot(Class = 'Machinery And Equipment', marker_color='rgb(147,112,219)', marker_line_color='rgb(75,0,130)',
H = 180, Horizontal = False)
AvgValue_Plot(Feat = 'Sector', H = 400, marker_color='MistyRose', marker_line_color='DarkRed')
AvgValue_Plot(Feat = 'Community Structure', H = 550, marker_color='CornSilk', marker_line_color='DarkOrange', yt = 35e6)
def Community_Ave_yr(Yr, Inp=Data):
Temp = Data[Data['Roll_Year']==Yr]
Out = pd.DataFrame(Temp.groupby('Community_Code')['Assessed_Value'].mean())
Out.columns =['Average Value']
Out = Out.reset_index()
del Temp
Temp = pd.merge(Community_Boundaries, Out, how ='inner', on ='Community_Code')
Out = Temp.copy()
del Temp
Out = Out[['Average Value', 'geometry']]
return Out
proj = gcrs.AlbersEqualArea(central_latitude = Data.Latitude.mean(), central_longitude = Data.Longitude.mean())
f, ax = plt.subplots(1, 2, figsize=(18, 12), subplot_kw={'projection': proj})
# Left Plot
Temp = Community_Ave_yr(Data.Roll_Year.max())
_ = gplt.choropleth(Temp, hue = 'Average Value', cmap='Blues', linewidth=0.0, ax = ax[0], legend=True,
legend_kwargs={'shrink': .5, "aspect":30})
_ = gplt.polyplot(Temp, edgecolor='black', linewidth=0.8, ax = ax[0])
_ = ax[0].set_title('Assessed Average Value by Community in %i'% Data.Roll_Year.max())
del Temp
# Right Plot
Temp = Community_Ave_yr(Data.Roll_Year.min())
_ = gplt.choropleth(Temp, hue = 'Average Value', cmap='Reds', linewidth=0.0, ax = ax[1], legend=True,
legend_kwargs={'shrink': .5, "aspect":30})
_ = gplt.polyplot(Temp, edgecolor='black', linewidth=0.6, ax = ax[1])
_ = ax[1].set_title('Assessed Average Value by Community in %i' % Data.Roll_Year.min())
del Temp
We can define the following heatmap to show the Assessed values in each community. In each case, the to fifty most values asses are also marked on the map.
def map_points(df, Zoom = 13, TOP = 10, heat_map_weights_col='Assessed_Value', Normalize=False, heat_map_radius=10):
M = folium.Map(location=[df['Latitude'].median(), df['Longitude'].median()], zoom_start = Zoom)
if heat_map_weights_col is None:
Cols = ['Latitude', 'Longitude']
else:
if Normalize:
df[heat_map_weights_col] = df[heat_map_weights_col] / df[heat_map_weights_col].sum()
Cols = ['Latitude', 'Longitude', heat_map_weights_col]
M.add_child(plugins.HeatMap(df[Cols].values, radius=heat_map_radius))
Tops = df.head(TOP)
for i in range(len(Tops)):
Inp=df[i:(i+1)]
St = '(Value:' + str(Inp.Assessed_Value.values[0])+', Class:' + Inp.Assessment_Class_Description.values[0] + ')'
if (Inp.Assessment_Class.values[0] == 'RE'):
folium.Marker(location=[Inp.Latitude.values[0], Inp.Longitude.values[0]], popup = St,
icon=folium.Icon(color='purple',icon='building', prefix='fa') ).add_to(M)
else:
folium.Marker(location=[Inp.Latitude.values[0], Inp.Longitude.values[0]], popup = St).add_to(M)
display(M)
For example, consider the Seton community.
Group = Data[Data.Roll_Year == Data.Roll_Year.max()]
Group = Group[Group['Community_Name'] == 'Seton']
map_points(Group, 14, 50)
del Group
Similarly, for the Brentwood community, we have,
Group = Data[Data.Roll_Year == Data.Roll_Year.max()]
Group = Group[Group['Community_Name'] == 'Brentwood']
map_points(Group, 14, 50)
del Group
Unfortunately, the given data are not suitable for any forms of predictions since we mainly know the location of an asset, and their classes and values. Hopefully, in the future, this study can be extended.